# =============================================================================
# Copyright (C) 2010 Diego Duclos
#
# This file is part of pyfa.
#
# pyfa is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyfa is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.    See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with pyfa.    If not, see <http://www.gnu.org/licenses/>.
# =============================================================================

# noinspection PyPackageRequirements
import wx
from logbook import Logger

from gui.auxWindow import AuxiliaryFrame
from gui.bitmap_loader import BitmapLoader
from gui.builtinViews.entityEditor import BaseValidator, EntityEditor
from gui.utils.clipboard import fromClipboard, toClipboard
from gui.utils.inputs import FloatBox
from service.damagePattern import DamagePattern, ImportError
from service.fit import Fit
from collections import OrderedDict

pyfalog = Logger(__name__)


class DmgPatternNameValidator(BaseValidator):
    def __init__(self):
        BaseValidator.__init__(self)

    def Clone(self):
        return DmgPatternNameValidator()

    def Validate(self, win):
        entityEditor = win.parent
        textCtrl = self.GetWindow()
        text = textCtrl.GetValue().strip()

        try:
            if len(text) == 0:
                raise ValueError("你必须为你的伤害配置文件起个名字!")
            elif text in [x.rawName for x in entityEditor.choices]:
                raise ValueError("伤害配置文件名字已被使用，请选择其他的。")

            return True
        except ValueError as e:
            pyfalog.error(e)
            wx.MessageBox("{}".format(e), "Error")
            textCtrl.SetFocus()
            return False


class DmgPatternEntityEditor(EntityEditor):
    def __init__(self, parent):
        EntityEditor.__init__(self, parent, "伤害配置文件")
        self.SetEditorValidator(DmgPatternNameValidator)

    def getEntitiesFromContext(self):
        sDP = DamagePattern.getInstance()
        choices = sorted(sDP.getUserDamagePatternList(), key=lambda p: p.rawName)
        choices = [c for c in choices if c.rawName != "Selected Ammo"]
        return choices

    def DoNew(self, name):
        sDP = DamagePattern.getInstance()
        return sDP.newPattern(name)

    def DoRename(self, entity, name):
        sDP = DamagePattern.getInstance()
        sDP.renamePattern(entity, name)

    def DoCopy(self, entity, name):
        sDP = DamagePattern.getInstance()
        copy = sDP.copyPattern(entity)
        sDP.renamePattern(copy, name)
        return copy

    def DoDelete(self, entity):
        sDP = DamagePattern.getInstance()
        sDP.deletePattern(entity)


class DmgPatternEditor(AuxiliaryFrame):

    #DAMAGE_TYPES = ("em", "thermal", "kinetic", "explosive")
    DAMAGE_TYPES = OrderedDict([
        ("em", "电磁抗性"),
        ("thermal", "热能抗性"),
        ("kinetic", "动能抗性"),
        ("explosive", "爆炸抗性")])

    def __init__(self, parent):
        super().__init__(
            parent, id=wx.ID_ANY, title="伤害模式编辑器", resizeable=True,
            # Dropdown list widget is scaled to its longest content line on GTK, adapt to that
            size=wx.Size(500, 240) if "wxGTK" in wx.PlatformInfo else wx.Size(400, 240))

        self.block = False
        self.SetSizeHints(wx.DefaultSize, wx.DefaultSize)

        mainSizer = wx.BoxSizer(wx.VERTICAL)

        self.entityEditor = DmgPatternEntityEditor(self)
        mainSizer.Add(self.entityEditor, 0, wx.ALL | wx.EXPAND, 2)

        self.sl = wx.StaticLine(self)
        mainSizer.Add(self.sl, 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

        contentSizer = wx.BoxSizer(wx.VERTICAL)
        self.embitmap = BitmapLoader.getBitmap("em_big", "gui")
        self.thermbitmap = BitmapLoader.getBitmap("thermal_big", "gui")
        self.kinbitmap = BitmapLoader.getBitmap("kinetic_big", "gui")
        self.expbitmap = BitmapLoader.getBitmap("explosive_big", "gui")

        dmgeditSizer = wx.FlexGridSizer(2, 6, 0, 2)
        dmgeditSizer.AddGrowableCol(0)
        dmgeditSizer.AddGrowableCol(5)
        dmgeditSizer.SetFlexibleDirection(wx.BOTH)
        dmgeditSizer.SetNonFlexibleGrowMode(wx.FLEX_GROWMODE_SPECIFIED)

        width = -1
        defSize = wx.Size(width, -1)

        for i, type_ in enumerate(self.DAMAGE_TYPES):
            bmp = wx.StaticBitmap(self, wx.ID_ANY, BitmapLoader.getBitmap("%s_big" % type_, "gui"))
            ttText = self.DAMAGE_TYPES[type_]
            if i % 2:
                style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT
                border = 20
            else:
                style = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT
                border = 5

            # set text edit
            editBox = FloatBox(parent=self, id=wx.ID_ANY, value=0, pos=wx.DefaultPosition, size=defSize)
            percLabel = wx.StaticText(self, wx.ID_ANY, "0%")
            setattr(self, "%sEdit" % type_, editBox)
            setattr(self, "%sPerc" % type_, percLabel)

            dmgeditSizer.Add(bmp, 0, style, border)
            dmgeditSizer.Add(editBox, 0, wx.BOTTOM | wx.TOP | wx.ALIGN_CENTER_VERTICAL, 5)
            dmgeditSizer.Add(percLabel, 0, wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5)

            editBox.Bind(wx.EVT_TEXT, self.OnFieldChanged)

        contentSizer.Add(dmgeditSizer, 1, wx.EXPAND | wx.ALL, 5)
        self.slfooter = wx.StaticLine(self)
        contentSizer.Add(self.slfooter, 0, wx.EXPAND | wx.TOP, 5)

        footerSizer = wx.BoxSizer(wx.HORIZONTAL)
        perSizer = wx.BoxSizer(wx.VERTICAL)

        self.stNotice = wx.StaticText(self, wx.ID_ANY, "")
        self.stNotice.Wrap(-1)
        perSizer.Add(self.stNotice, 0, wx.BOTTOM | wx.TOP | wx.LEFT, 5)

        footerSizer.Add(perSizer, 1, wx.ALIGN_CENTER_VERTICAL, 5)

        self.totSizer = wx.BoxSizer(wx.VERTICAL)

        contentSizer.Add(footerSizer, 0, wx.EXPAND, 5)

        mainSizer.Add(contentSizer, 1, wx.EXPAND, 0)

        self.SetSizer(mainSizer)

        importExport = (("Import", wx.ART_FILE_OPEN, "from"),
                        ("Export", wx.ART_FILE_SAVE_AS, "to"))

        for name, art, direction in importExport:
            bitmap = wx.ArtProvider.GetBitmap(art, wx.ART_BUTTON)
            btn = wx.BitmapButton(self, wx.ID_ANY, bitmap)

            btn.SetMinSize(btn.GetSize())
            btn.SetMaxSize(btn.GetSize())

            btn.Layout()
            setattr(self, name, btn)
            btn.Enable(True)
            nametype={"Export":"导出","Import":"导入"}
            directiontype={"from":"从","to":"到"}
            btn.SetToolTip("%s 模式 %s 剪贴板" % (nametype[name], directiontype[direction]))
            footerSizer.Add(btn, 0)
            btn.Bind(wx.EVT_BUTTON, getattr(self, "{}Patterns".format(name.lower())))

        if not self.entityEditor.checkEntitiesExist():
            self.Close()
            return

        self.Layout()
        bsize = self.GetBestSize()
        self.SetSize((-1, bsize.height))
        self.SetMinSize(self.GetSize())
        self.CenterOnParent()

        self.Bind(wx.EVT_CHOICE, self.patternChanged)
        self.Bind(wx.EVT_CHAR_HOOK, self.kbEvent)

        self.inputTimer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnInputTimer, self.inputTimer)

        self.patternChanged()

    def OnFieldChanged(self, event=None):
        if event is not None:
            event.Skip()
        self.inputTimer.Stop()
        self.inputTimer.Start(Fit.getInstance().serviceFittingOptions['marketSearchDelay'], True)

    def OnInputTimer(self, event):
        event.Skip()
        if self.block:
            return
        p = self.entityEditor.getActiveEntity()
        total = sum([(getattr(self, "%sEdit" % attr).GetValueFloat() or 0) for attr in self.DAMAGE_TYPES])
        for type_ in self.DAMAGE_TYPES:
            editBox = getattr(self, "%sEdit" % type_)
            percLabel = getattr(self, "%sPerc" % type_)
            setattr(p, "%sAmount" % type_, editBox.GetValueFloat() or 0)
            percLabel.SetLabel("%.1f%%" % ((editBox.GetValueFloat() or 0) * 100 / total if total > 0 else 0))
        self.totSizer.Layout()
        DamagePattern.getInstance().saveChanges(p)

    def restrict(self):
        for type_ in self.DAMAGE_TYPES:
            editObj = getattr(self, "%sEdit" % type_)
            editObj.Enable(False)
        self.entityEditor.btnRename.Enable(False)
        self.entityEditor.btnDelete.Enable(False)

    def unrestrict(self):
        for type_ in self.DAMAGE_TYPES:
            editObj = getattr(self, "%sEdit" % type_)
            editObj.Enable()
        self.entityEditor.btnRename.Enable()
        self.entityEditor.btnDelete.Enable()

    def patternChanged(self, event=None):

        if not self.entityEditor.checkEntitiesExist():
            self.Close()
            return

        p = self.entityEditor.getActiveEntity()

        if p is None:
            return

        if p.rawName == "Uniform" or p.rawName == "Selected Ammo":
            self.restrict()
        else:
            self.unrestrict()

        self.block = True

        for field in self.DAMAGE_TYPES:
            edit = getattr(self, "%sEdit" % field)
            amount = int(round(getattr(p, "%sAmount" % field)))
            edit.ChangeValueFloat(amount)

        self.block = False
        self.OnFieldChanged()

    def __del__(self):
        pass

    def importPatterns(self, event):
        text = fromClipboard()
        if text:
            sDP = DamagePattern.getInstance()
            try:
                sDP.importPatterns(text)
                self.stNotice.SetLabel("模式成功的从剪贴板导入")
            except ImportError as e:
                pyfalog.error(e)
                self.stNotice.SetLabel(str(e))
            except (KeyboardInterrupt, SystemExit):
                raise
            except Exception as e:
                msg = "Could not import from clipboard: unknown errors"
                pyfalog.warning(msg)
                pyfalog.error(e)
                self.stNotice.SetLabel(msg)
            finally:
                self.entityEditor.refreshEntityList()
        else:
            self.stNotice.SetLabel("无法从剪贴板导入")

    def exportPatterns(self, event):
        sDP = DamagePattern.getInstance()
        toClipboard(sDP.exportPatterns())
        self.stNotice.SetLabel("模式导出到剪贴板")

    def kbEvent(self, event):
        if event.GetKeyCode() == wx.WXK_ESCAPE and event.GetModifiers() == wx.MOD_NONE:
            self.Close()
            return
        event.Skip()
